<!DOCTYPE html>
<html manifest="todoist.manifest">
<head><title>Todoist</title>
<link rel="shortcut icon" href="http://todoist.com/favicon.ico">
<link rel="apple-touch-icon" href="todoist57.png">
<link rel="apple-touch-icon" sizes="114x114" href="todoist114.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<script>
function $(s) {
  return document.getElementById(s);
}

var todoist = {
  data: {},
  countdown: 0,
  projCount: 0,
  afterLogin: [],

  ajax: function(m, p, ssl) {
    var s = document.createElement("script");
    s.src = (ssl ? "https:/" : "http:/") 
      + "/todoist.com/API/" 
      + m 
      + "?&callback=todoist.cb" + m 
      + (this.token ? "&token=" + this.token : "") 
      + (p || "")
      + "&.rand=" + Math.random();
    document.getElementsByTagName("head")[0].appendChild(s);
  },

  cookie: function(n, v, remove) {
    if(remove) {
      document.cookie = encodeURIComponent(n) + "=; expires=Mon, 1 Jan 1980 01:01:01 GMT";
    } else if(v) {
      document.cookie = encodeURIComponent(n) + "=" + 
        encodeURIComponent(v) + "; expires=" + 
        new Date(new Date().getTime() + 30*24*60*60*1000).toGMTString();
    } else {
      var s = " " + document.cookie + ";";
      var i = s.indexOf(" " + n + "=");
      if(i >= 0) return decodeURIComponent(s.substring(s.indexOf("=", i) + 1, s.indexOf(";",i + 1)));
    }
  },

  onload: function() {
    this.token = this.cookie("tdtoken") || null;

    var dis = this;
    this.transaction(function(t) {
      t.executeSql(
        "SELECT * FROM projs", [],
        function(t, r) {
          r = r.rows;
          if(r.length == 0) return dis.goOnline();
          for(var i=0; i<r.length; i++) dis.data[r.item(i).id] = {name: r.item(i).name, order:r.item(i).item_order};
        }
      );
      t.executeSql(
        "SELECT * FROM tasks", [],
        function(t, r) {
          r = r.rows;
          if(r.length == 0) return dis.goOnline();

          for(var i=0; i<r.length; i++) {
            var proj = dis.data[r.item(i).project_id];
            if(!proj.data) proj.data = [];

            var tmp = r.item(i).due_date;

            proj.data.push({
              id: r.item(i).id,
              project_id: r.item(i).project_id,
              content: r.item(i).content,
              due_date: tmp ? new Date(tmp.substr(0,4), 1*tmp.substring(5,7)-1, tmp.substring(8,10), 23, 59, 59) : null,
              priority: r.item(i).priority
            });
          }

          dis.projCount = 0;
          for(var i in dis.data) {
            if(dis.data[i].data) dis.projCount++;
          }
          dis.sortView();
          dis.updateView(1);
        }
      );
    }, function(e) {
      dis.goOnline();
    });
  },

  goOnline: function() {
    scrollTo(0, 0);
    if(this.token) {
      this.ajax("getProjects");
      $("upd").style.WebkitTransform = "rotate(-180deg)";
    } else {
      $("loginbox").style.display = "block";
      $("loginnow").value = "Login";
      $("loginnow").disabled = false;
      var n;
      if(n = $("intro")) n.style.display = "";
      if(n = $("filler")) n.style.display = "none";
    }
  },

  login: function() {
      var u = $("user").value;
      var p = $("pass").value.replace(/^\s|\s$/g,"");

      if(p.length > 30 && /^[0-9a-f]+$/.test(p) && confirm("Login with private token?")) {
        this.cblogin({api_token: encodeURIComponent(p)});

      } else {
        $("loginnow").value = "Loading...";
        $("loginnow").disabled = true;
        u = "&email="+encodeURIComponent(u)+"&password="+encodeURIComponent(p);
        this.ajax("login", u, true);
        p = this;
        this.loginTimeout = setTimeout(function() {p.ajax("login", u);}, 7000);
      }
  },

  cblogin: function(r) {
    $("loginnow").value = "Login";
    $("loginnow").disabled = false;
    clearTimeout(this.loginTimeout);

    if(typeof r == "string") {
      $("loginbox").style.display = "";
      alert("Error: "+r);

    } else {
      $("loginbox").style.display = "none";

      this.token = r.api_token;
      this.cookie("tdtoken", this.token);

      var al = this.afterLogin;
      if(al.length) {
        for(var i=0; i<al.length; i++) {
          if(al[i]) this.ajax(al[i][0], al[i][1]);
        }
      } else {
        this.ajax("getProjects");
        $("upd").style.WebkitTransform = "rotate(-180deg)";
      }
    }
  },

  cbgetProjects: function(r) {
    this.projCount = 0;

    if(typeof r == "string") {
      alert("Error: "+r);
      this.token = null;
      this.goOnline();
    }

    this.data = {};
    for(var i=0; i<r.length; i++) {
      this.data[r[i].id] = {name: r[i].name, order: r[i].item_order||0};
      this.countdown++;
      this.ajax("getUncompletedItems", "&js_date=1&project_id=" + r[i].id);
    }

    var d = this.data;
    this.transaction(function(t) {
      t.executeSql("DELETE FROM projs");
      t.executeSql("DELETE FROM tasks");
      for(var i in d) {
        t.executeSql("INSERT INTO projs (id, name, item_order) VALUES (?, ?, ?)", [i, d[i].name, d[i].order]);
      }
    });
  },

  cbgetUncompletedItems: function(r) {
    this.countdown--;
    $("upd").style.WebkitTransform = "rotate(-"+this.countdown+"0deg)";

    if(r && r.length) {
      this.data[r[0].project_id].data = r;
      this.projCount++;
      for(var i=0; i<r.length; i++) r[i].content = r[i].content.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
      this.sortView(r[0].project_id);

      this.transaction(function(t) {  //used by addItem
        t.executeSql("DELETE FROM tasks WHERE project_id = ?", [r[0].project_id]);
      });
    }

    if(this.countdown == 0) this.updateView();

    if(r && r.length) {
      var d = this.data[r[0].project_id].data;

      this.transaction(function(t) {
        var tmp, pad = function(i) {return i < 10 ? "0" + i : i};

        for(var i=0; i<d.length; i++) {

          tmp = d[i].due_date;  //new Date("Sun Apr 29 23:59:59 2007")
          if(tmp) tmp = tmp.getFullYear() + "-" + pad(tmp.getMonth() + 1) + "-" + pad(tmp.getDate());

          t.executeSql(
            "INSERT INTO tasks (id, project_id, content, due_date, priority) VALUES (?, ?, ?, ?, ?)", 
            [d[i].id, d[i].project_id, d[i].content, tmp, d[i].priority]
          );
        }
      });
    }
  },

  sortView: function(proj) {
    var d = this.data, item, diff;
    var now = new Date().getTime();
    if(proj) {
      d = {};
      d[proj] = this.data[proj];
    }

    for(var i in d) {
      if(!d[i].data) continue;
      for(var j=0, x=0; j<d[i].data.length; j++) {
        item = d[i].data[j];
        item.due_now = 0;
        if(item.due_date) {
          diff = item.due_date.getTime() - now;
          item.due_now = diff < 60000*60*24 ? 2 : diff < 60000*60*24*7 ? 1 : 0;
          if(item.due_now == 2) {
            d[i].data.splice(j, 1);
            d[i].data.unshift(item);
          } else if(j != x) {
            d[i].data.splice(j, 1);
            d[i].data.splice(x, 0, item);
          }
          x++;
        }
      }
    }
  },

  updateView: function(silent) {
    var html = [], summary = [];
    var item;
    var diff;

    var projs = [];  //sort projs

    var found;
    for(var i in this.data) {
      item = this.data[i].order;
      found = false;
      for(var j=0; j<projs.length; j++) {
        if(this.data[projs[j]].order >= item) {
          projs.splice(j, 0, i);
          found = true;
          break;
        }
      }
      if(!found) projs.push(i);
    }

    for(var i=0; i<projs.length; i++) {
      var proj = this.data[projs[i]];
      if(!proj.data) continue;

      html.push("<div class='proj'><h2><a href='javascript:if(todoist.copying){todoist.copyItem("+projs[i]+");}else{todoist.addItem("+projs[i]+");}' ondragover='if(todoist.copying&&event.preventDefault)event.preventDefault();' ondrop='todoist.copyItem("+projs[i]+");' ontouchstart='touchIsClick(this);' id='p"+projs[i]+"'>"+proj.name+"</a></h2><ul>");
      for(var j=0; j<proj.data.length; j++) {
        item = proj.data[j];
        html.push("<li class='imp"+item.priority+(j%2?" alt eta":" eta")+item.due_now+"' id='n" + item.id+"_"+projs[i]+"' onclick='if(todoist.copying)todoist.selectItem(this);else todoist.completeItems(this);' ondragstart='todoist.copying={};todoist.selectItem(this);' ondragend='todoist.copyItem(null);'>"+item.content+"<span class='due'>"+(item.due_date?(item.due_date.getMonth()+1)+"<span class='div'>/</span>"+item.due_date.getDate():"")+"</span></li>");

        if(item.due_now == 2) {
          diff = item.due_date.getTime();
          for(var k=0; k<summary.length; k++) {
            if(diff >= summary[k].due_date.getTime()) {
              summary.splice(k, 0, item);
              diff = 0;
              break;
            }
          }
          if(diff) summary.push(item);
        }
      }
      html.push("</ul></div>");
    }

    var width = this.projCount || 1;

    if(this.projCount > 1 && summary.length) {
      width++;
      for(var i=0; i<summary.length; i++) {
        item = summary[i];
        summary[i] = "<li class='imp"+item.priority+(i%2?" alt":"")+" eta2' id='s" + item.id+"_"+item.project_id+"' onclick='if(todoist.copying)todoist.selectItem(this);else todoist.completeItems(this);'>"+item.content+"<span class='due'>"+(item.due_date?(item.due_date.getMonth()+1)+"<span class='div'>/</span>"+item.due_date.getDate():"")+"</span></li>";
      }
      html.unshift("<div class='proj sum'><h2><b>"+new Date().toDateString()+"</b></h2><ul>" + summary.join("") + "</ul></div>");
    }

    if(this.projCount == 0) html.push("<p>List is empty.</p>");

    html.push("<div class='emptyprojs'>");

    for(var i=0; i<projs.length; i++) {
      var proj = this.data[projs[i]];
      if(!proj.data) html.push("<a href='javascript:if(todoist.copying)todoist.copyItem("+projs[i]+");else todoist.addItem("+projs[i]+");'>"+proj.name+"</a> ");
    }
    html.push("<a href='javascript:todoist.addProject();'>[+]</a></div>");

    $("main").innerHTML = html.join("");
    if(!silent) {
      setTimeout(function() {
        document.body.className = wob ? "flash white" : "flash";
        setTimeout(function() {document.body.className = wob ? "white" : "";}, 100);
      }, 100);
    }
  },

  addItem: function(id) {
    if(!this.token) {
      this.goOnline();
      this.afterLogin.push(null);
    }

    var s = prompt("What to add to '"+this.data[id].name+"'?", this.lastInput || "");
    var ds = s ? prompt("Remind when? d/m/yyyy", (new Date().getHours() < 18 ? "today" : "tom")) : null;
    if(s) {
      if(this.token) {
        this.ajax("addItem", "&project_id="+id+"&priority=1&js_date=1&content="+encodeURIComponent(s)+(ds?"&date_string="+encodeURIComponent(ds):""));
      } else {
        this.afterLogin.push(["addItem", "&project_id="+id+"&priority=1&js_date=1&content="+encodeURIComponent(s)+(ds?"&date_string="+encodeURIComponent(ds):"")]);
      }
      this.lastInput = s;
    }
  },

  cbaddItem: function(r) {
    if(typeof r == "string") {
      alert(r);
    } else {
      r.content = r.content.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
      var p = this.data[r.project_id];
      if(!p.data) {
        p.data = [];
        this.projCount++;
      }
      p.data.push(r);
      this.sortView(r.project_id);
      this.updateView();

      $("n"+r.id+"_"+r.project_id).className += " fresh";

      this.transaction(function(t) {
        var pad = function(i) {return i < 10 ? "0" + i : i};

        //new Date("Sun Apr 29 23:59:59 2007")
        var tmp = !r.due_date ? null : r.due_date.getFullYear() + "-" + pad(r.due_date.getMonth() + 1) + "-" + pad(r.due_date.getDate());

        t.executeSql(
          "INSERT INTO tasks (id, project_id, content, due_date, priority) VALUES (?, ?, ?, ?, ?)", 
          [r.id, r.project_id, r.content, tmp, r.priority]
        );
      });
      this.lastInput = "";
    }
  },

  completeItems: function(n) {
    var id = n.id.split("_"), proj = id[1];
    id = id[0].substr(1);
    if(confirm("Item done?")) {
      if(this.token) {
        this.ajax("completeItems", "&ids=%5B" + id + "%5D");
      } else {
        this.afterLogin.push(["completeItems", "&ids=%5B" + id + "%5D"]);
        this.goOnline();
      }
      if((n = $("n"+id+"_"+proj))) n.parentNode.removeChild(n);
      if((n = $("s"+id+"_"+proj))) n.parentNode.removeChild(n);
      this.transaction(function(t) {
        t.executeSql("DELETE FROM tasks WHERE id = ?", [id]);
      });
      var arr = this.data[proj].data;
      for(var i=0; i<arr.length; i++) if(arr[i].id == id) return arr.splice(i, 1);
    }
  },

  cbcompleteItems: function(r) {
    document.body.className = wob ? "flash white" : "flash";
    setTimeout(function() {document.body.className = wob ? "white" : "";}, 100);
  },

  updateItem: function(n_id) {
    var id = n_id.split("_"), proj = id[1];
    id = id[0].substr(1);

    if(!this.token) {
      this.goOnline();
      this.afterLogin.push(null);
    }

    var i, arr = this.data[proj].data;
    for(i=0; i<arr.length; i++) {
      if(arr[i].id == id) break;
    }

    var dateStr = arr[i].due_date;
    if(dateStr) dateStr = dateStr.getDate() + "/" + (dateStr.getMonth() + 1) + "/" + dateStr.getFullYear();

    var s = prompt("Change to:", arr[i].content);
    var ds = s ? prompt("Remind when? d/m/yyyy", dateStr) : "";
    if(s) {
      arr[i].content = s;
      arr[i].date_string = ds;
      arr[i].due_date = null;
      var params = ["js_date=1"];
      for(var j in arr[i]) {
        params.push(j + "=" + encodeURIComponent(arr[i][j] || ""));
      }

      if(this.token) {
        this.ajax("updateItem", "&" + params.join("&"));
      } else {
        this.afterLogin.push(["updateItem", "&" + params.join("&")]);
      }
    }
  },

  cbupdateItem: function(r) {
    if(typeof r == "string") {
      alert(r);
    } else {
      var arr = this.data[r.project_id].data;
      for(var i=0; i<arr.length; i++) {
        if(arr[i].id == r.id) {
          arr[i] = r;
          break;
        }
      }

      this.transaction(function(t) {
        var tmp = r.due_date, pad = function(i) {return i < 10 ? "0" + i : i};
        if(tmp) tmp = tmp.getFullYear() + "-" + pad(tmp.getMonth() + 1) + "-" + pad(tmp.getDate());

        t.executeSql(
          "UPDATE tasks SET project_id=?, content=?, due_date=?, priority=? WHERE id=?", 
          [r.project_id, r.content, tmp, r.priority, r.id]
        );
      });

      this.sortView(r.project_id);
      this.updateView();

      $("n"+r.id+"_"+r.project_id).className += " fresh";
    }
  },

  addProject: function() {
    if(!this.token) {
      this.goOnline();
      this.afterLogin.push(null);
    }

    var s = prompt("Project name?");

    if(s) {
      s = encodeURIComponent(s);
      if(this.token) {
        this.ajax("addProject", "&name="+s);
      } else {
        this.afterLogin.push(["addProject", "&name="+s]);
      }
    }
  },

  cbaddProject: function(r) {
    if(typeof r == "string") {
      alert("Error: "+r);
      return;
    }

    var d = this.data[r.id] = {name: r.name, order: r.item_order||0};

    this.transaction(function(t) {
      t.executeSql("INSERT INTO projs (id, name, item_order) VALUES (?, ?, ?)", [r.id, d.name, d.order]);
    });

    this.updateView();
  },

  makeCopyable: function() {
    if(this.copying) {
      this.copying = null;
      $("main").className = "";
    } else {
      this.copying = {};
      $("main").className = "copy1";
    }
  },

  selectItem: function(n) {
    if(this.copying.id) {
      this.copying = null;
      $("main").className = "";
      return;
    }

    var id = n.id.split("_"), proj = id[1], arr = this.data[proj].data;
    id = id[0].substr(1);

    for(var i=0; i<arr.length; i++) {
      if(arr[i].id == id) {
        this.copying = arr[i];
        $("main").className = "copy2";
        break;
      }
    }
  },

  copyItem: function(proj) {
    var m = this.copying;
    this.copying = null;
    $("main").className = "";

    if(!proj || m.project_id == proj) return;

    var d = m.due_date || "";  //new Date("Sun Apr 29 23:59:59 2007")
    var params = ["js_date=1&project_id=" + proj + (!d ? "" : "&date_string=" + d.getDate() + "%2F" + (d.getMonth()+1) + "%2F" + d.getFullYear())];
    for(var i in m) {
      if(m[i] && i != "project_id" && i != "id" && i != "due_date") params.push(i + "=" + encodeURIComponent(m[i] || ""));
    }

    if(this.token) {
      this.ajax("addItem", "&" + params.join("&"));
    } else {
      this.goOnline();
      this.afterLogin.push(["addItem", "&" + params.join("&")]);
    }
  },

  search: function() {
    var s = this.searchTerm = prompt("Search for?", this.searchTerm || "");

    var arr = document.getElementsByTagName("i");
    for(var i=arr.length-1; i>=0; i--) arr[i].parentNode.replaceChild(arr[i].firstChild, arr[i]);

    if(s) {
      s = s.toLowerCase().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
      var n, n1, n2, d, proj={}, count = 0;
      for(var i in this.data) {
        d = this.data[i].data;
        if(!d) continue;
        for(var j=0; j<d.length && count < 100; j++) {
          if(d[j].content.toLowerCase().indexOf(s) >= 0) {
            n = $("n" + d[j].id + "_" + d[j].project_id);
            var n2 = n.removeChild(n.lastChild);
            n.innerHTML = n.innerHTML.toLowerCase().split(s).join("<i>" + s + "</i>");
            n.appendChild(n2);

            proj[d[j].project_id] = 1;

            if(count == 0 && n.getBoundingClientRect) {
              n = n.getBoundingClientRect();
              scrollTo(document.body.scrollLeft + n.left - 40, document.body.scrollTop + n.top - 40);
            }
            count++;
          }
        }
      }

      for(var j in proj) if(n = $("p" + j)) n.innerHTML = "<i>" + n.innerHTML + "</i>";

      if(count == 0) alert("No matches found");
    }
  },

  logout: function() {
    this.transaction(function(t) {
      t.executeSql("DELETE FROM projs");
      t.executeSql("DELETE FROM tasks");
    });
    this.cookie("tdtoken", 0, 1);
    this.cookie("tdwidths", 0, 1);
    $("user").value = "";
    $("pass").value = "";
    this.projCount = this.token = 0;
    this.data = {};
    this.updateView(1);
    this.goOnline();
  },

  transaction: function(a, b, c) {
    var f = new Function("");
    b = b || f;
    c = c || f;
    if(!this.dbms) {
      this.dbms = [[a, b, c]];
      var _dbms, dis = this;
      try {
        _dbms = window.openDatabase("todoist-dashboard", "1.0", "Tasks", 5*1024*1024);
        _dbms.transaction(
          function(t) {
            t.executeSql("CREATE TABLE IF NOT EXISTS tasks (id INTEGER, project_id INTEGER, content TEXT, due_date DATE, priority TINYINT)");
            t.executeSql("CREATE TABLE IF NOT EXISTS projs (id INTEGER, name TEXT, item_order INTEGER)");
          }, function(e) {
            dis.transaction = f;
            for(var i=0; i<dis.dbms.length; i++) dis.dbms[i][1](e);
          }, function() {  //ok
            for(var i=0; i<dis.dbms.length; i++) _dbms.transaction.apply(_dbms, dis.dbms[i]);
            dis.dbms = _dbms;
          }
        );
      } catch(e) {
        this.transaction = f;
        for(var i=0; i<this.dbms.length; i++) this.dbms[i][1](e);
      }
    } else if(this.dbms.transaction) {
      this.dbms.transaction(a, b, c);
    } else {
      this.dbms.push([a, b, c]);
    }
  }
};
</script>
<style>
body {margin:3px; padding:1px; background:#000; color:#fff; -webkit-tap-highlight-color:rgba(255,255,255,0.2); -webkit-text-size-adjust:100%}
body,form,#foot {font:11pt Helvetica,Arial}
#foot {background:#000; color:#aaa; clear:both}
body.flash {background:#333}
.proj {float:left; width:32%; margin:1em 5px; padding:0; box-sizing:border-box; -moz-box-sizing:border-box; -webkit-box-sizing:border-box}
.proj h2 {margin:0; padding:0; font:bold 125% Helvetica,Arial}
.proj h2 a {text-decoration:none; padding:0 1em 0.3em 0.7em}
.token, .token a {color:#aaa}
a {font-size:100%; color:#fff}
.emptyprojs {font-size:100%} .emptyprojs a {color:#999; margin-right:1em; text-decoration:none}
.due {color:#bbf; font-size:90%; margin-left:6px}
.due:not(:empty) {background:rgba(255,255,255,0.15); padding:0 0.3em; border-radius:0.5em}
.white .due:not(:empty) {background:rgba(0,0,0,0.05)}
li .div {margin:0 0.1em}
.eta1, .eta2 {background:#222; border-color:#333}
.eta2 {background:#333; border-color:#444}
.white .eta1 {background:#ffc; border-color:#eeb}
.white .eta2 {background:#fdd; border-color:#ecc}
.sum h2 {padding:0 0.7em; color:#444}
.sum h2 b {font-size:70%}
.sum .eta2 {background:none; border-color:#333}
.white .sum .eta2 {border-color:#eee}
ul {border:1px solid #444}
.white ul {border-color:#ddd}
ul,li {padding:0; margin:0; list-style:none; vertical-align:middle; word-wrap:break-word}
li {padding:0.5em 0 0.5em 1.2em; border-bottom:1px solid #333; text-indent:-0.8em; color:#ccc; -moz-border-radius:0.6em; cursor:pointer; -webkit-transition:margin 0.3s; -webkit-user-drag:element}
li:last-child {border:0}
.white li {border-color:#eee}
li:hover {-webkit-user-select:none}
#main .proj ul {max-height:461px; overflow-y:auto; -webkit-overflow-scrolling:touch}
#main li:-webkit-drag {background:#000; color:#fff}
li.alt {color:#fff}
li.imp2 {color:#0c0} li.imp3 {color:#88f} li.imp4 {color:#f00}
ul>li.imp4.eta2 {background:#733; color:#fff}
@media screen and (max-width: 800px) {.proj {width:45%}}
@media screen and (max-device-width: 480px) {body,form,#foot{font-size:13pt} .proj {margin:0} .proj > ul {width:320px; border:0} #main {display:table-row} #main .proj {float:none; display:table-cell}}
.proj i {font-style:normal; background:#ff4; padding:0 0.1em; -moz-border-radius:0.3em; border-radius:0.3em; color:#000}
#foot a {padding:0.3em 0.5em; margin-top:1em}
#upd {-webkit-transition:-webkit-transform 0.5s}
.fresh {-webkit-animation:darkflash 3s 1 ease-in}
.white .fresh {-webkit-animation:lightflash 3s 1 ease-in}
.white #main li:-webkit-drag {background:#fff; color:#000}
.white .proj i {background:#cc0; color:#fff}
.white, .white #foot {background:#fff; color:#000}
.white .emptyprojs a {color:#bbb}
.white a {color:#555}
.white .due {color:#33f}
.white .sum h2 {color:#ccc}
.white li {color:#888}
.white li.alt {color:#000}
.white li.imp2 {color:#1d1} .white li.imp3 {color:#44f} .white li.imp4 {color:#f44}
.white ul>li.imp4.eta2 {background:#fcc; color:#000}
.copy1 li {margin-top:0.3em}
.copy1 .proj h2 a, .copy2 .proj h2 a  {border-radius:0.3em; -webkit-transition:background-color 0.5s}
.copy1 li {background:#555}
.copy2 .proj h2 a {background:#555}
.white .copy1 li {background:#ffa}
.white .copy2 .proj h2 a {background:#ffa}
.resizeme {display:none}
#intro .proj {width:32%}
@media print {#main .proj{float:none;width:auto;-webkit-column-count:4;-webkit-column-gap:1em;-moz-column-count:4;-moz-column-gap:1em;border-bottom:1px dashed #888} #foot{display:none}}
@-webkit-keyframes darkflash {from {background:#880}}
@-webkit-keyframes lightflash {from {background:#ffb}}
.proj ::-webkit-scrollbar {width:8px; height:8px}
.proj ::-webkit-scrollbar-thumb {background-color: #666; -webkit-box-shadow: inset -1px -1px 0 #888}
.white .proj ::-webkit-scrollbar-thumb {background-color: #ccc; -webkit-box-shadow: inset 1px 1px 0 #aaa}
</style>
</head>
<body style="overflow:auto">
<form id="loginbox" style="margin:5px;padding:0;display:none" onsubmit="todoist.login();return false;">
Email:<br><input id="user" type="email" autocorrect="off" autocapitalize="off">
<br>Password: <span class="token">or <a href="http://getsatisfaction.com/todoist/topics/how_do_i_get_an_api_token" tabindex="-1">Private Token</a></span><br><input id="pass" type="password">
<br><input type="submit" id="loginnow" value="Login"> <a href="http://todoist.com">Register</a>
</form>
<noscript style="color:#f55">Please enable JavaScript.</noscript>
<div id="main"><div id="intro" style="display:none">
<div class="proj"><h2><a href="#">what is Todoist Wall?</a></h2><ul><li>an <a href="http://simpleajax.googlecode.com/svn/docs/demos/todoist.html" style="text-decoration:none">iPhone web app that syncs with your Todoist</a></li><li class="alt">can be read offline. needs connection to add</li><li>large readable text</li><li class="alt">designed for the iPhone screen</li><li>works just as good on your computer's browser</li><li class="alt">view all your todos on one large wall</li><li>get to all your todos just by sliding your finger</li></ul></div>
<div class="proj"><h2><a href="#">instructions</a></h2><ul><li>login with your todoist account</li><li class="alt">tap on an item to mark as done</li><li>tap on item and hold to edit</li><li class="alt">tap on project title to add a task</li><li>pinch to zoom</li><li class="alt">slide across to view other projects</li><li>add it to your iPhone home screen</li></ul></div>
<div class="proj"><h2><a href="#">todo karma</a></h2><ul><li>add a date only if a task has a deadline</li><li class="alt">items with deadlines appear at the top</li><li>due and overdue items appear shaded</li><li class="alt">use all lowercase to save time</li><li>create Projects according to your life. e.g., grocery, yacht, wedding</li><li class="alt">add things asap lest you forget</li></ul></div>
</div>
<div id="filler" style="margin-bottom:1000px;width:3000px;clear:both"></div>
</div>
<div id="foot">
<div id="man" style="display:none">
Todoist for iPhone -
<br>(1) click on project title to add a task
<br>(2) press and hold on task to edit
<br>(3) tap on task to delete
<br>(4) type !p4 while adding a task to mark it as important
<br>(5) add website to home screen to remove Safari buttons
<br><a href="javascript:todoist.logout();scrollTo(0,0);">logout</a> 
<a href="javascript:todoist.makeCopyable();scrollTo(0,0);">duplicate task</a>
<a href="http://code.google.com/p/simpleajax/wiki/TodoistWall">wiki</a>
</div>
<div id="upd" style="display:inline-block;margin-left:-5px"><a href="javascript:;" onclick="todoist.goOnline();return false;" style="padding:2px;text-decoration:none;font-weight:bold" accesskey="u">&dArr;</a></div>
<a href="#" onclick="with($('man').style){display=display?'':'none';};return false;" style="padding:3px">?</a>
<a href="javascript:todoist.search();" accesskey="s" title="shortcut key: Alt+S">search</a>
</div>
<script>
var isTouch = ("ontouchend" in document.body);
todoist.onload();
var wob = (location.hash == "#w");
if(wob) document.body.className = "white";
var ok = 200;
</script>
<script defer="defer">
var touchTimer = function(e) {clearTimeout(touchTimer);};
document.body[isTouch ? "ontouchstart" : "onmousedown"] = function(e) {
  clearTimeout(touchTimer);
  e = !e ? event.srcElement : e.target || e.srcElement;
  if(e && e.nodeType != 1) e = e.parentNode;
  if(e && e.id && todoist.data) {
    touchTimer = setTimeout("todoist.updateItem('"+e.id+"');", 900);
  }
};
document.body[isTouch ? "ontouchmove" : "onmousemove"] = touchTimer;
document.body[isTouch ? "ontouchend" : "onmouseup"] = touchTimer;
document.body.ongesturestart = touchTimer;

function touchIsClick(n, s) {
  n.setAttribute("ontouchstart", (s = n.href));
  n.href = "javascript:void(0);";
  eval(s);
}
</script>
</body>
</html>